#ifndef MMU_H
#define MMU_H
#include "types.h"
#include "cpu_instr.h"

#define PDE_CNT 1024
#define PTE_CNT 1024

#define PDE_P   (1 << 0)
#define PTE_P   (1 << 0)
#define PDE_W   (1 << 1) //write enable
#define PTE_W   (1 << 1)
#define PDE_U   (1 << 2) //user access
#define PTE_U   (1 << 2)


typedef union _pde_t{
    uint32_t v;
    struct {
        uint32_t present : 1;
        uint32_t write_enable :1;
        uint32_t user_mode_acc :1;
        uint32_t write_through :1;
        uint32_t cache_disable :1;
        uint32_t accessed :1;
        uint32_t : 1;
        uint32_t ps : 1;
        uint32_t : 4;
        uint32_t phy_pt_addr: 20;
    };
}pde_t;

typedef union _pte_t{
    uint32_t v;
    struct {
        uint32_t present : 1;
        uint32_t write_enable :1;
        uint32_t user_mode_acc :1;
        uint32_t write_through :1;
        uint32_t cache_disable :1;
        uint32_t accessed :1;
        uint32_t dirty : 1;
        uint32_t pat : 1;
        uint32_t global :1;
        uint32_t : 3;
        uint32_t phy_page_addr: 20;
    };
}pte_t;
//2-level page table, pde and pte
//vaddr: 10bit directory, 10bit table, 12bit offset
static inline void mmu_set_page_dir(uint32_t paddr){
    write_cr3(paddr);
}
//get directory bit 22~31
static inline uint32_t pde_index(uint32_t vaddr){
    int index = (vaddr >> 22);
    return index;
}
//get table bit 12~21
static inline uint32_t pte_index(uint32_t vaddr){
    return (vaddr >> 12) & 0x3FF;//get the index refer to base pte table
}
//get offset bit 0~11
static inline uint32_t pte_offset(uint32_t vaddr){
    return vaddr & 0xFFF;
}
static inline uint32_t pde_paddr(pde_t * pde){
    return pde->phy_pt_addr << 12;//the directory << 12 equals to the addr of base pte, 20+12=32
}
static inline uint32_t pte_paddr(pte_t * pte){
    return pte->phy_page_addr << 12;
}
static inline uint32_t get_pte_perm(pte_t * pte){
    return (pte->v & 0x1FF);
}
#endif // !MMU_H
